/***************************************************************
 *
 * (c) 2008 Markus Dittrich 
 *
 * This program is free software; you can redistribute it 
 * and/or modify it under the terms of the GNU General Public 
 * License Version 3 as published by the Free Software Foundation. 
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License Version 3 for more details.
 *
 * You should have received a copy of the GNU General Public 
 * License along with this program; if not, write to the Free 
 * Software Foundation, Inc., 59 Temple Place - Suite 330, 
 * Boston, MA 02111-1307, USA.
 *
 ****************************************************************/

#ifndef PROPERTY_WIDGETS_H 
#define PROPERTY_WIDGETS_H

/* boost includes */
#include <boost/tuple/tuple.hpp>
#include <boost/utility.hpp>

/* STL includes */
#include <vector>

/* Qt includes */
#include <QColor>
#include <QString>
#include <QWidget>

/* local includes */
#include "data_object.h"
#include "plot_properties.h"
#include "utilities.h"

/* forward declarations */
class QCheckBox;
class QComboBox;
class QGridLayout;
class QGroupBox;
class QHBoxLayout;
class QLabel;
class QPushButton;
class QRadioButton;
class QSpinBox;
class QString;
class QTableWidget;
class QTableWidgetItem;
class QVBoxLayout;


/* integer value indicating that a data selector has
 * ELEMENT count set */
const int HAS_ELEMENT_COUNT = 0;



/****************************************************************
 *
 * class BasePropertyWidget provides the interface for 
 * different kinds of property widgets
 *
 * NOTE: The constructor only does the basic initialization 
 * of object data structures. The actual bootstraping of the
 * widget is done in the Init(...) function which can
 * accept parameters with additional data specific to a 
 * particular derived object.
 *
 ****************************************************************/
class BasePropertyWidget : public QWidget
{

  Q_OBJECT

public:

  explicit BasePropertyWidget(QWidget* parent, 
    const QString& dataName, DataObjectPtr theData, 
    PlotPropertiesPtr plotProperties);
  virtual ~BasePropertyWidget() = 0;
      
  virtual const QString& get_name() const = 0;
  virtual void update_widget(DataObjectPtr newData) = 0;


protected:

  explicit BasePropertyWidget(QWidget* parent);
};



/****************************************************************
 *
 * class DataPropertyWidget implements a widget for displaying 
 * properties and manipulating an individial data set
 *
 ****************************************************************/
class DataPropertyWidget 
  : 
    public BasePropertyWidget,
    public boost::noncopyable
{

  Q_OBJECT


public:

  explicit DataPropertyWidget(QWidget* parent, 
      const QString& DataName, DataObjectPtr theData, 
      PlotPropertiesPtr plotProperties);
  bool Init(); 

  void update_widget(DataObjectPtr newData);
  const QString& get_name() const;


signals:

  void update_canvas();
  void color_changed(const QString&, const QColor&);
  void update_and_rescale_canvas();


private slots:

  void change_color_();
  void on_lineStyle_change_(QString lineType);
  void x_data_selection_changed_(int selection);
  void y_data_selection_changed_(int selection);
  void change_line_width_(int newWidth);


private:

  /* indicates successful construction */
  int status_;

  /* private members functions */
  void populate_main_layout_();
  void generate_main_layout_();
  void generate_num_dataitems_label_();
  void generate_plot_property_selectors_();
  void generate_xy_data_selectors_();

  void generate_property_table_();
  void populate_property_table_();
  void populate_property_table_with_x_data_(
    const std::vector<double>& data);
  void populate_property_table_with_y_data_(
    const std::vector<double>& data);

  void set_penStyle_map_();
  Qt::PenStyle find_penStyle_(QString searchString);

  void update_num_dataitems_label_();

  /* Qt widgets located on DataPropertyWidget */
  QVBoxLayout* mainLayout_;
 
  QString numDataItemsString_;
  QLabel* numDataItemsLabel_; 

  QRadioButton* visibilityButton_;

  QGridLayout* plotPropertiesLayout_;
  QPushButton* plotColorChooser_;

  QGridLayout* xyDataSelectorLayout_;
  QComboBox* xDataChooser_;
  QComboBox* yDataChooser_;
 
  QTableWidgetItem* xMinItem_;
  QTableWidgetItem* yMinItem_;
  QTableWidgetItem* xMaxItem_;
  QTableWidgetItem* yMaxItem_;
  QTableWidgetItem* xMeanItem_;   
  QTableWidgetItem* yMeanItem_;
  QTableWidgetItem* xMedianItem_;   
  QTableWidgetItem* yMedianItem_;
  QTableWidgetItem* xStdItem_;   
  QTableWidgetItem* yStdItem_;

  /* std::vector holding line style properties */
  std::vector<QString> penStyleContainer_;

  /* property table widget */
  QTableWidget* propertyTable_;
  static const int NUM_ROWS_ = 5;
  static const int NUM_COLUMNS_ = 2;
  static const int COLUMN_WIDTH_ = 75;
  static const int ROW_HEIGHT_ = 20;
  static const int PROPERTY_TABLE_HEIGHT_ = 130;

  /* data pointers needed for this property tab */
  const QWidget* parent_;
  QString dataName_;
  PlotPropertiesPtr plotProperties_; // can't be const since 
  DataObjectPtr data_;               // they may change
};
 



/****************************************************************
 *
 * class HistogramPropertyWidget implements a widget for 
 * displaying properties and manipulating a histogram data set
 *
 ****************************************************************/
class HistogramPropertyWidget 
  : 
    public BasePropertyWidget,
    public boost::noncopyable
{

  Q_OBJECT


public:

  explicit HistogramPropertyWidget(QWidget* parent, 
      const QString& histgramName, DataObjectPtr theData, 
      PlotPropertiesPtr plotProperties, bool isNormalized);
  bool Init(int numBins, const QString& dataName); 

  void update_widget(DataObjectPtr);
  const QString& get_name() const;


signals:

  void update_canvas();
  void color_changed(const QString&, const QColor&);
  void update_and_rescale_canvas();
  void recompute_histogram(const QString& dataName, 
      const QString& histogramName, int newNumberOfBins, 
      bool recompute);


private slots:

  void change_color_();
  void change_line_width_(int newWidth);
  void number_of_bins_changed_();


private:

  /* indicates successful construction */
  int status_;

  /* pointer to parent */
  const QWidget* parent_;

  /* private members functions */
  void populate_main_layout_();
  void generate_main_layout_();
  void generate_name_label_();
  void generate_property_table_();
  void generate_plot_property_selectors_();
  void generate_bin_control_selectors_();
  void populate_property_table_();

  /* widgets */
  QVBoxLayout* mainLayout_;
  QGroupBox* nameLabelGrouper_;
  QGridLayout* plotPropertiesLayout_;
  QGridLayout* binControlLayout_;
  QPushButton* plotColorChooser_;
  QSpinBox* numBinsSelector_;
  QCheckBox* normalizeSelector_;
  QTableWidgetItem* minItem_;
  QTableWidgetItem* maxItem_;
  QTableWidgetItem* meanItem_;
  QTableWidgetItem* medianItem_;

  /* data members */
  int numBins_;
  bool normalized_;
 
  /* property table widget */
  QTableWidget* propertyTable_;
  static const int NUM_ROWS_ = 4;
  static const int NUM_COLUMNS_ = 1;
  static const int COLUMN_WIDTH_ = 135;
  static const int ROW_HEIGHT_ = 20;
  static const int PROPERTY_TABLE_HEIGHT_ = 110;

  /* data pointers needed for this property tab */
  QString dataName_;
  QString histogramName_;            
  PlotPropertiesPtr plotProperties_; // can't be const since 
  DataObjectPtr data_;               // they may change
};
  

/*****************************************************************
 *
 * declaration of helper functions
 *
 *****************************************************************/
void set_widget_fore_color_(QWidget* aWidget, QColor aColor);
void set_widget_back_color_(QWidget* aWidget, QColor aColor);


#endif
